package com.secsbrain.development.biz.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.secsbrain.cmdb.client.iface.AppInfoService;
import com.secsbrain.common.ErrorCodeEnum;
import com.secsbrain.common.ResponseResult;
import com.secsbrain.common.ResponseVo;
import com.secsbrain.cmdb.client.model.App;
import com.secsbrain.cmdb.client.model.AppDetail;
import com.secsbrain.common.utils.DateTimeUtils;
import com.secsbrain.common.utils.HttpClientUtil;
import com.secsbrain.development.biz.IBranchService;
import com.secsbrain.development.biz.IProjectService;
import com.secsbrain.development.biz.exception.ProjectException;
import com.secsbrain.development.biz.model.BranchMerge;
import com.secsbrain.development.biz.model.BranchParam;
import com.secsbrain.development.biz.model.ProjectParam;
import com.secsbrain.development.dal.mapper.BranchActionRecordMapper;
import com.secsbrain.development.dal.mapper.RecordMapper;
import com.secsbrain.development.dal.model.BranchActionRecord;
import com.secsbrain.development.dal.model.Record;

import com.secsbrain.development.biz.constant.EnumDefinition;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.RowBounds;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

@Service
public class ProjectServiceImpl implements IProjectService {

    private static final Logger logger = LoggerFactory.getLogger(ProjectServiceImpl.class);

    /**
     * app缓存
     */
    private Map<Long, App> appCache = new ConcurrentHashMap<>();

    @Autowired
    IBranchService branchService;

    @Autowired
    RecordMapper recordMapper;

    @Autowired
    AppInfoService appInfoService;

    @Autowired
    BranchActionRecordMapper branchActionRecordMapper;

    public static final String UPSTREAM_BRANCH = "master";

    @Value("${deploy.api.server.host:http://127.0.0.1:8001}")
    private String serverHost;

    public static final String PLAN_URL = "/api/open/plan/create";

    public static final String CLOSE_PLAN_URL = "/api/open/plan/close";

    public void loadData() {
        logger.debug("加载App数据开始。。。");

        appCache.clear();
        
        ResponseVo<List<App>> appResult=appInfoService.queryAllAppList(null,null,null,null,null,null);
        List<App> list = appResult.getData();

        for (App app : list) {
            appCache.put(app.getId(), app);
        }
    }

    @Override
    public ResponseResult createProject(ProjectParam projectParam) {
        logger.debug("立项开始......参数：{}", projectParam);
        if (projectParam.getBranchTypeId() == null) {
            return new ResponseResult<>(ErrorCodeEnum.ERROR_COMMON_PARAM.getCode(), "分支类型ID不能为空");
        }

        if (StringUtils.isEmpty(projectParam.getProjectName())) {
            return new ResponseResult<>(ErrorCodeEnum.ERROR_COMMON_PARAM.getCode(), "项目名称不能为空");
        }

        if (StringUtils.isEmpty(projectParam.getProjectIds())) {
            return new ResponseResult<>(ErrorCodeEnum.ERROR_COMMON_PARAM.getCode(), "立项至少需要一个应用");
        }

        Map<String, String> map = new HashMap<>();
        for (String str : Arrays.asList(projectParam.getProjectIds().split(","))) {
            map.put(str, "");
        }

        for (String str : Arrays.asList(projectParam.getUpstreamProjectIds().split(","))) {
            if (map.containsKey(str)) {
                return new ResponseResult<>(ErrorCodeEnum.ERROR_COMMON_PARAM.getCode(), "上游应用重复！");
            }
        }

        String branchName = "";
        for (String projectId : projectParam.getProjectIds().split(",")) {
            BranchParam branchParam = new BranchParam();
            branchParam.setBranchTypeId(projectParam.getBranchTypeId());
            branchParam.setSourceBranch(projectParam.getSourceBranch());
            branchParam.setProjectId(Long.parseLong(projectId));
            ResponseResult<String> branchResult = branchService.createBranch(branchParam);
            if (StringUtils.isEmpty(branchResult.getData())) {
                return new ResponseResult<>(ErrorCodeEnum.ERROR_COMMON_PARAM.getCode(), branchResult.getMsg());
            }
            branchName = branchResult.getData();
            logger.debug("立项创建分支结果：{}", branchResult);
        }

        Record recordParam = new Record();
        recordParam.setBranchName(branchName);
        recordParam.setPrjName(projectParam.getProjectName());
        EntityWrapper<Record> entityWrapper=new EntityWrapper<Record>(recordParam);
		List<Record> recordList = recordMapper.selectList(entityWrapper);
        if (CollectionUtils.isNotEmpty(recordList)) {
            return new ResponseResult<>(ErrorCodeEnum.ERROR_COMMON_PARAM.getCode(), "项目名称/分支重复");
        }

        try {
            ((ProjectServiceImpl) AopContext.currentProxy()).createPlan(branchName, projectParam);
        } catch (IOException e) {
            logger.error("", e);
            return new ResponseResult<>(ErrorCodeEnum.ERROR_COMMON_PARAM.getCode(), "网络错误");
        } catch (ProjectException e) {
            logger.warn("", e);
            return new ResponseResult<>(ErrorCodeEnum.ERROR_COMMON_PARAM.getCode(), "立项失败：" + e.getMessage());
        }

        return new ResponseResult<>();
    }

    private String getEnvName() {
        //如果名称已经存在，则在后面加1
        String namePrex = "dev";
//        int i = 0;
//        while (true) {
//            String index = "";
//            if (i > 0) {
//                index = String.valueOf(i);
//            }
//            Record recordParam = new Record();
//            recordParam.setStatus(0);
//            recordParam.setEnvName(namePrex + index);
//            List<Record> records = recordMapper.select(recordParam);
//            if (CollectionUtils.isEmpty(records)) {
//                return namePrex + index;
//            }
//
//            i++;
//        }
        return namePrex;
    }

    @Transactional
    public void createPlan(String branchName, ProjectParam projectParam) throws IOException {
        Record record = new Record();
        record.setBranchName(branchName);
        record.setCreateTime(DateTimeUtils.now());
        record.setCreateUser(projectParam.getCreateUser());
        record.setEnvName(this.getEnvName());
        record.setPrjName(projectParam.getProjectName());
        record.setProjectIds(projectParam.getProjectIds());
        record.setUpstreamProjectIds(projectParam.getUpstreamProjectIds());
        record.setStatus(0);
        recordMapper.insertSelective(record);

        Map<String, Object> params = new HashMap<>();
        params.put("env", record.getEnvName());
        params.put("projectName", projectParam.getProjectName());
        params.put("creator", projectParam.getCreateId());
        params.put("projectDesc", projectParam.getProjectName());

        List<Map<String, Object>> projectIdList = new ArrayList<>();
        for (String str : Arrays.asList(projectParam.getProjectIds().split(","))) {
            Map<String, Object> map = new HashMap<>();
            map.put("id", Long.parseLong(str));
            map.put("branch", branchName);
            projectIdList.add(map);
        }

        if (StringUtils.isNotEmpty(projectParam.getUpstreamProjectIds())) {
            for (String str : Arrays.asList(projectParam.getUpstreamProjectIds().split(","))) {
                Map<String, Object> map = new HashMap<>();
                map.put("id", Long.parseLong(str));
                map.put("branch", UPSTREAM_BRANCH);
                projectIdList.add(map);
            }
        }

        params.put("appList", projectIdList);

        String jsonStr = HttpClientUtil.postRequest(serverHost + PLAN_URL, JSON.toJSONString(params));
        logger.debug("创建发布计划返回结果：{}", jsonStr);
        Map<?, ?> resMap = JSON.parseObject(jsonStr, Map.class);
        if (!resMap.containsKey("status") || !((JSONObject) resMap.get("status")).getBooleanValue("success")) {
            throw new ProjectException("创建发布计划失败");
        }

        Record recordUp = new Record();
        recordUp.setId(record.getId());
        recordUp.setResId(((JSONObject) resMap.get("data")).getInteger("id"));
        recordMapper.updateSelectiveById(recordUp);
    }

    @Transactional
    public void updatePlan(Record record, ProjectParam projectParam, List<String> projects, List<String> upstreamProjects) throws IOException {
        Record recordUp = new Record();
        recordUp.setId(projectParam.getId());
        recordUp.setPrjName(projectParam.getProjectName());
        recordUp.setProjectIds(StringUtils.join(projects, ","));
        recordUp.setUpstreamProjectIds(StringUtils.join(upstreamProjects, ","));
        recordMapper.updateSelectiveById(recordUp);

        //有新增应用才调发布计划接口
        if (StringUtils.isNotEmpty(projectParam.getProjectIds()) || StringUtils.isNotEmpty(projectParam.getUpstreamProjectIds())) {
            Map<String, Object> params = new HashMap<>();
            params.put("projectId", record.getResId());//发布计划ID
            params.put("env", record.getEnvName());
            params.put("projectName", projectParam.getProjectName());
            params.put("creator", projectParam.getCreateId());
            params.put("projectDesc", projectParam.getProjectName());

            List<Map<String, Object>> projectIdList = new ArrayList<>();
            for (String str : projects) {
                Map<String, Object> map = new HashMap<>();
                map.put("id", Long.parseLong(str));
                map.put("branch", record.getBranchName());
                projectIdList.add(map);
            }

            for (String str : upstreamProjects) {
                Map<String, Object> map = new HashMap<>();
                map.put("id", Long.parseLong(str));
                map.put("branch", UPSTREAM_BRANCH);
                projectIdList.add(map);
            }

            params.put("appList", projectIdList);

            String jsonStr = HttpClientUtil.postRequest(serverHost + PLAN_URL, JSON.toJSONString(params));
            logger.debug("修改发布计划返回结果：{}", jsonStr);
            Map<?, ?> resMap = JSON.parseObject(jsonStr, Map.class);
            if (!resMap.containsKey("status") || !((JSONObject) resMap.get("status")).getBooleanValue("success")) {
                throw new ProjectException("创建发布计划失败");
            }
        }
    }
    
    private App getApp(Long appId){
    	ResponseVo<AppDetail> responseVo=appInfoService.queryAppDetailById(appId);
    	AppDetail appDetail=responseVo.getData();
    	App app=new App();
    	app.setId(appDetail.getId());
    	app.setName(appDetail.getName());
    	app.setOwnerName(appDetail.getOwnerName());
    	return app;
    }

    @Override
    public ResponseResult<Page<Record>> queryPrjList(Integer start, Integer limit, Record recordParam) {
        try {
            int count = recordMapper.selectCount(recordParam);
            Page<Record> pageList=new Page<>(start,limit);
            pageList.setTotal(count);

			//用到查询条件再改
            EntityWrapper<Record> entityWrapper=new EntityWrapper<>(recordParam, "create_time desc");
            List<Record> list = recordMapper.selectPage(new RowBounds(start, limit), entityWrapper);

            for (Record record : list) {
                List<Map<String, Object>> appList = new ArrayList<>();

                StringBuilder builder1 = new StringBuilder();
                for (String str : Arrays.asList(record.getProjectIds().split(","))) {
                    Map<String, Object> map = new HashMap<>();
                    map.put("appId", Long.parseLong(str));

                    App app = null;
                    //如果缓存里有，则直接从缓存里取，否则从数据库查
                    if (appCache.containsKey(Long.parseLong(str))) {
                        app = appCache.get(Long.parseLong(str));
                    } else {
                    	//TODO 此处轮询要改掉
                        app = getApp(Long.parseLong(str));
                    }

                    builder1.append(app.getName() + ",");
                    map.put("appName", app.getName());
                    map.put("owner", app.getOwnerName());

                    appList.add(map);
                }
                record.setAppList(appList);
                record.setProjectNames(builder1.deleteCharAt(builder1.length() - 1).toString());

                List<Map<String, Object>> upstreamAppList = new ArrayList<>();

                if (StringUtils.isNotEmpty(record.getUpstreamProjectIds())) {
                    StringBuilder builder2 = new StringBuilder();

                    App app = null;
                    for (String str : Arrays.asList(record.getUpstreamProjectIds().split(","))) {
                        Map<String, Object> map = new HashMap<>();
                        map.put("appId", Long.parseLong(str));

                        if (appCache.containsKey(Long.parseLong(str))) {
                            app = appCache.get(Long.parseLong(str));
                        } else {
                        	//TODO 此处轮询要改掉
                            app = getApp(Long.parseLong(str));
                        }

                        builder2.append(app.getName() + ",");
                        map.put("appName", app.getName());
                        map.put("owner", app.getOwnerName());

                        upstreamAppList.add(map);
                    }

                    record.setUpstreamAppList(upstreamAppList);
                    record.setUpstreamProjectNames(builder2.deleteCharAt(builder2.length() - 1).toString());
                }

                record.setFormatTime(DateTimeUtils.parseDateAsString(record.getCreateTime(), "yyyy-MM-dd HH:mm:ss"));
            }

            pageList.setRecords(list);
            return new ResponseResult<>(pageList);
        } catch (Exception e) {
            logger.error("", e);
            return new ResponseResult<>(ErrorCodeEnum.ERROR_COMMON_SYSTEM.getCode(),e.getMessage());
        }
    }

    @Override
    public ResponseResult modifyProject(ProjectParam projectParam) {
        logger.debug("修改项目开始......参数：{}", projectParam);

        if (projectParam.getId() == null) {
            return new ResponseResult<>(ErrorCodeEnum.ERROR_COMMON_PARAM.getCode(),"项目ID不能为空");
        }

        if (StringUtils.isEmpty(projectParam.getProjectName())) {
            return new ResponseResult<>(ErrorCodeEnum.ERROR_COMMON_PARAM.getCode(),"项目名称不能为空");
        }

        Record record = recordMapper.selectById(projectParam.getId());
        if (record == null) {
            return new ResponseResult<>(ErrorCodeEnum.ERROR_COMMON_PARAM.getCode(),"没有查询到立项记录");
        }

        if (record.getStatus() != 0) {
            return new ResponseResult<>(ErrorCodeEnum.ERROR_COMMON_PARAM.getCode(),"此项目的状态不正确，无法修改");
        }

        if (this.isInclude(record.getProjectIds(), projectParam.getProjectIds())) {
            return new ResponseResult<>(ErrorCodeEnum.ERROR_COMMON_PARAM.getCode(),"新增应用中不能包含已有应用");
        }

        if (this.isInclude(record.getUpstreamProjectIds(), projectParam.getUpstreamProjectIds())) {
            return new ResponseResult<>(ErrorCodeEnum.ERROR_COMMON_PARAM.getCode(),"新增上游应用中不能包含已有上游应用");
        }

        Map<String, List<String>> prjMap = this.getPrjList(record, projectParam);
        List<String> projects = prjMap.get("projects");
        List<String> upstreamProjects = prjMap.get("upstreamProjects");

        Map<String, String> map = new HashMap<>();
        for (String str : projects) {
            map.put(str, "");
        }

        for (String str : upstreamProjects) {
            if (map.containsKey(str)) {
                return new ResponseResult<>(ErrorCodeEnum.ERROR_COMMON_PARAM.getCode(),"上游应用重复！");
            }
        }

        if (!StringUtils.isEmpty(projectParam.getProjectIds())) {
            BranchActionRecord branchActionParam = new BranchActionRecord();
            branchActionParam.setProjectId(Long.parseLong(record.getProjectIds().split(",")[0]));
            branchActionParam.setBranchName(record.getBranchName());
            branchActionParam.setActionType(EnumDefinition.BranchActionType.PULL.getCode());
            BranchActionRecord branchActionRecord = branchActionRecordMapper.selectOne(branchActionParam);
            if (branchActionRecord == null) {
                return new ResponseResult<>(ErrorCodeEnum.ERROR_COMMON_PARAM.getCode(),"没有查询到相应的分支记录");
            }

            for (String projectId : projectParam.getProjectIds().split(",")) {
                BranchParam branchParam = new BranchParam();
                branchParam.setBranchTypeId(branchActionRecord.getBranchTypeId());
                branchParam.setSourceBranch(branchActionRecord.getRelateBranch());
                branchParam.setProjectId(Long.parseLong(projectId));
                ResponseResult<String> branchResult = branchService.createBranch(branchParam);
                if (StringUtils.isEmpty(branchResult.getData())) {
                    return new ResponseResult<>(ErrorCodeEnum.ERROR_COMMON_PARAM.getCode(),branchResult.getMsg());
                }
                logger.debug("修改项目创建分支结果：{}", branchResult);
            }
        }

        try {
            ((ProjectServiceImpl) AopContext.currentProxy()).updatePlan(record, projectParam, projects, upstreamProjects);
        } catch (IOException e) {
            logger.error("", e);
            return new ResponseResult<>(ErrorCodeEnum.ERROR_COMMON_PARAM.getCode(), "网络错误");
        } catch (ProjectException e) {
            logger.warn("", e);
            return new ResponseResult<>(ErrorCodeEnum.ERROR_COMMON_PARAM.getCode(), "修改项目失败：" + e.getMessage());
        }

        return new ResponseResult<>();
    }

    private Map<String, List<String>> getPrjList(Record record, ProjectParam projectParam) {
        Map<String, List<String>> map = new HashMap<>();

        List<String> projectList = new ArrayList<>();
        projectList.addAll(Arrays.asList(record.getProjectIds().split(",")));
        if (StringUtils.isNotEmpty(projectParam.getProjectIds())) {
            projectList.addAll(Arrays.asList(projectParam.getProjectIds().split(",")));
        }

        map.put("projects", projectList);

        List<String> upstreamProjectList = new ArrayList<>();
        if (StringUtils.isNotEmpty(record.getUpstreamProjectIds())) {
            upstreamProjectList.addAll(Arrays.asList(record.getUpstreamProjectIds().split(",")));
        }
        if (StringUtils.isNotEmpty(projectParam.getUpstreamProjectIds())) {
            upstreamProjectList.addAll(Arrays.asList(projectParam.getUpstreamProjectIds().split(",")));
        }

        map.put("upstreamProjects", upstreamProjectList);
        return map;
    }

    private boolean isInclude(String projectIds, String addProjectIds) {
        if (StringUtils.isEmpty(projectIds) || StringUtils.isEmpty(addProjectIds)) {
            return false;
        }

        for (String projectId : projectIds.split(",")) {
            for (String addProjectId : addProjectIds.split(",")) {
                if (projectId.equals(addProjectId)) {
                    return true;
                }
            }
        }

        return false;
    }

    @Override
    public ResponseResult overProject(ProjectParam projectParam) {
        if (projectParam.getId() == null) {
            return new ResponseResult<>(ErrorCodeEnum.ERROR_COMMON_PARAM.getCode(),"项目ID不能为空");
        }

        Record record = recordMapper.selectById(projectParam.getId());
        if (record == null) {
            return new ResponseResult<>(ErrorCodeEnum.ERROR_COMMON_PARAM.getCode(),"没有查询到立项记录");
        }

        for (String projectId : record.getProjectIds().split(",")) {
            BranchMerge branchMerge = new BranchMerge();
            branchMerge.setBranchName(record.getBranchName());
            branchMerge.setProjectId(Long.parseLong(projectId));
            ResponseResult mergeResult = branchService.mergeBranch(branchMerge);
            logger.debug("【分支名," + record.getBranchName() + ",应用ID," + projectId + ",】合并结果：", mergeResult);
        }

        //调用关闭发布计划接口
        String jsonStr = HttpClientUtil.getRequest(serverHost + CLOSE_PLAN_URL + "/" + record.getResId(),null);
        logger.debug("关闭发布计划返回结果：{}", jsonStr);
        Map<?, ?> resMap = JSON.parseObject(jsonStr, Map.class);
        if (!resMap.containsKey("status") || !((JSONObject) resMap.get("status")).getBooleanValue("success")) {
            return new ResponseResult<>(ErrorCodeEnum.ERROR_COMMON_PARAM.getCode(),"关闭发布计划失败");

        }

        Record recordUp = new Record();
        recordUp.setId(projectParam.getId());
        recordUp.setStatus(1);//改为已结项
        recordMapper.updateSelectiveById(recordUp);

        return new ResponseResult<>();
    }

}
